package vip.ola.merchant.paydemo.ctrl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import vip.ola.core.common.util.DateUtil;
import vip.ola.merchant.common.config.MainConfig;
import vip.ola.merchant.common.ctrl.BaseController;
import vip.ola.merchant.common.service.RpcCommonService;
import vip.ola.core.common.constant.Constant;
import vip.ola.core.common.domain.BizResponse;
import vip.ola.core.common.domain.PayPageRes;
import vip.ola.core.common.util.HttpClient;
import vip.ola.core.common.util.PayDigestUtil;
import vip.ola.core.entity.MchInfo;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

import static vip.ola.core.common.constant.Constant.MCH_ROLE_NORMAL;

@RestController
@RequestMapping(Constant.MCH_CONTROLLER_ROOT_PATH + "/paydemo")
public class PaydemoController extends BaseController {

    private static final Logger _log = LoggerFactory.getLogger(PaydemoController.class);

    @Autowired
    private RpcCommonService rpcCommonService;

    @Autowired
    private MainConfig mainConfig;

    /**
     * 通道测试- 创建支付订单
     *
     * @param request
     * @return
     */
    @PreAuthorize("hasRole('" + MCH_ROLE_NORMAL + "')")
    @RequestMapping(value = "/create")
    @ResponseBody
    public ResponseEntity<?> create(HttpServletRequest request) {
        String productId = request.getParameter("productId");
        String amount = request.getParameter("amount");
        String subject = request.getParameter("subject");
        String body = request.getParameter("body");
        String notifyUrl = request.getParameter("notifyUrl");
        String returnUrl = request.getParameter("returnUrl");
        String extra = request.getParameter("extra");

        BigDecimal amountB = new BigDecimal(amount);
        amountB = amountB.multiply(new BigDecimal("100")).setScale(0);
        MchInfo mchInfo = rpcCommonService.rpcMchInfoService.findByMchId(this.getUser().getId());

        JSONObject retObj = createPayOrder(mchInfo.getMchId(), mchInfo.getPrivateKey(), productId, amountB.toString(), subject, body, notifyUrl, returnUrl, extra);
        if (retObj == null) {
            return ResponseEntity.ok(new BizResponse(10001, "创建订单失败,没有返回数据"));
        }
        if ("SUCCESS".equals(retObj.get("retCode"))) {
            // 验签
            String checkSign = PayDigestUtil.getSign(retObj, mchInfo.getPrivateKey(), "sign");
            String retSign = (String) retObj.get("sign");
            if (checkSign.equals(retSign)) {
                return ResponseEntity.ok(PayPageRes.buildSuccess(retObj));
            } else {
                return ResponseEntity.ok(new BizResponse(10001, "创建订单失败,验证支付中心返回签名失败"));
            }
        }
        return ResponseEntity.ok(new BizResponse(10001, "创建订单失败," + retObj.getString("retMsg")));
    }


    /**
     * 接收支付中心通知
     *
     * @param request
     * @param response
     * @throws Exception
     */
    @RequestMapping("/notify.htm")
    @ResponseBody
    public String doNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
        _log.info("====== 开始处理支付中心异步通知 ======");
        Map<String, Object> paramMap = request2payResponseMap(request, new String[]{
                "payOrderId", "mchId", "productId", "outTradeNo", "amount", "status",
                "channelOrderNo", "channelAttach", "param1", "income",
                "param2", "paySuccTime", "backType", "sign"
        });
        MchInfo mchInfo = rpcCommonService.rpcMchInfoService.findByMchId(Long.parseLong(paramMap.get("mchId").toString()));

        _log.info("支付中心通知请求参数,paramMap={}", paramMap);
        if (!verifyPayResponse(paramMap, mchInfo.getPrivateKey())) {
            String errorMessage = "verify request param failed.";
            _log.warn(errorMessage);
            return errorMessage;
        }
        String payOrderId = (String) paramMap.get("payOrderId");
        String mchOrderNo = (String) paramMap.get("outTradeNo");
        String resStr;
        try {
            // 业务处理代码,根据订单号,得到业务系统交易数据.
            // 对交易数据进行处理,如修改状态,发货等操作
            resStr = "success";
        } catch (Exception e) {
            resStr = "fail";
            _log.error("处理通知失败", e);
        }
        _log.info("响应支付中心通知结果:{},payOrderId={},mchOrderNo={}", resStr, payOrderId, mchOrderNo);
        _log.info("====== 支付中心通知处理完成 ======");
        return resStr;
    }

    /**
     * 处理界面跳转
     *
     * @param request
     * @param response
     * @throws Exception
     */
    @RequestMapping("/return.htm")
    @ResponseBody
    public String doRetrun(HttpServletRequest request, HttpServletResponse response) throws Exception {
        _log.info("====== 开始处理支付中心前端跳转 ======");
        return "处理完成";
    }

    /**
     * 调用Pay支付系统,创建支付订单
     *
     * @param mchId
     * @param key
     * @param productId
     * @param amount
     * @param subject
     * @param body
     * @param notifyUrl
     * @return
     */
    JSONObject createPayOrder(Long mchId, String key, String productId, String amount,
                              String subject, String body, String notifyUrl, String returnUrl, String extra) {
        JSONObject paramMap = new JSONObject();
        paramMap.put("mch_id", mchId);                               // 商户ID
        paramMap.put("out_trade_no", System.currentTimeMillis());     // 商户订单号
        paramMap.put("product_id", productId);                       // 支付产品
        paramMap.put("amount", amount);                             // 支付金额,单位分
        paramMap.put("subject", subject);                           // 商品标题
        paramMap.put("body", body);                                 // 商品内容
        paramMap.put("notify_url", notifyUrl);                       // 回调URL
        paramMap.put("return_url", returnUrl);                       // 跳转URl
        paramMap.put("param1", "");                                 // 扩展参数1
        paramMap.put("param2", "");                                 // 扩展参数2
        paramMap.put("extra", extra);                               // 附加参数
        // 生成签名数据
        String reqSign = PayDigestUtil.getSign(paramMap, key);
        paramMap.put("sign", reqSign);                              // 签名
        String reqData = "params=" + paramMap.toJSONString();
        _log.info("[pay] req:{}", reqData);
        String url = mainConfig.getPayUrl() + "/pay/create?";
        // 发起Http请求下单
        String result = call4Post(url + reqData);
        _log.info("[pay] res:{}", result);
        JSONObject retObj = JSON.parseObject(result);
        return retObj;
    }
    
//    public static void main(String[] args) {
//        Map signMap = new HashMap();
//        signMap.put("mchId", "9000");
//        signMap.put("productId", "8017");
//        signMap.put("mchOrderNo", "MZ202011152620608817");
//        signMap.put("amount", "10");
//        signMap.put("returnUrl", "http://pay.tspay888.com/notify/index/index.html");
//        signMap.put("notifyUrl", "http://pay.tspay888.com/notify/oula/index.html");
//        signMap.put("subject", "VIP");
//        signMap.put("body", "VIP");
//        signMap.put("param1", "");
//        signMap.put("param2", "");
//        signMap.put("extra", "23.100.93.148");
//
//        String reqSign = PayDigestUtil.getSign(signMap, "HXTNOHJNRO4Z5JKGTWGOEEVAUXFRA8ODDJTEKY5JKBBNXWAUBQ8MJVIOM9O04FOB42J5WYT9TAYPAERFYSSRYEXLYCCIPXZMZAK4YQ5UBSDUD9NJB1M5KI2ULRU03IAR");
//        System.out.println(reqSign);
//    }

    public Map<String, Object> request2payResponseMap(HttpServletRequest request, String[] paramArray) {
        Map<String, Object> responseMap = new HashMap<>();
        for (int i = 0; i < paramArray.length; i++) {
            String key = paramArray[i];
            String v = request.getParameter(key);
            if (v != null) {
                responseMap.put(key, v);
            }
        }
        return responseMap;
    }

    public boolean verifyPayResponse(Map<String, Object> map, String priKey) {
        String mchId = (String) map.get("mchId");
        String payOrderId = (String) map.get("payOrderId");
        String amount = (String) map.get("amount");
        String sign = (String) map.get("sign");

        if (StringUtils.isEmpty(mchId)) {
            _log.warn("Params error. mchId={}", mchId);
            return false;
        }
        if (StringUtils.isEmpty(payOrderId)) {
            _log.warn("Params error. payOrderId={}", payOrderId);
            return false;
        }
        if (StringUtils.isEmpty(amount) || !NumberUtils.isDigits(amount)) {
            _log.warn("Params error. amount={}", amount);
            return false;
        }
        if (StringUtils.isEmpty(sign)) {
            _log.warn("Params error. sign={}", sign);
            return false;
        }

        // 验证签名
        if (!verifySign(map, priKey)) {
            _log.warn("verify params sign failed. payOrderId={}", payOrderId);
            return false;
        }

        // 此处需要写业务逻辑
        // 校验数据,订单是否一致,金额是否一致

        return true;
    }

    public boolean verifySign(Map<String, Object> map, String privateKey) {
        String localSign = PayDigestUtil.getSign(map, privateKey, "sign");
        String sign = (String) map.get("sign");
        return localSign.equalsIgnoreCase(sign);
    }

    /**
     * 发起HTTP/HTTPS请求(method=POST)
     *
     * @param url
     * @return
     */
    public static String call4Post(String url) {
        try {
            URL url1 = new URL(url);
            if ("https".equals(url1.getProtocol())) {
                return HttpClient.callHttpsPost(url);
            } else if ("http".equals(url1.getProtocol())) {
                return HttpClient.callHttpPost(url);
            } else {
                return "";
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        return "";
    }


    /**
     * 通道测试- 创建支付订单
     *
     * @param request
     * @return
     */
    @PreAuthorize("hasRole('" + MCH_ROLE_NORMAL + "')")
    @RequestMapping(value = "/agentpay")
    @ResponseBody
    public ResponseEntity<?> transfer(HttpServletRequest request) {
        String amount = request.getParameter("amount");
        String accountAttr = request.getParameter("accountAttr");
        String accountName = request.getParameter("accountName");   // 收款人账户名
        String accountNo = request.getParameter("accountNo");       // 收款人账户号
        String notifyUrl = request.getParameter("notifyUrl");
        String extra = request.getParameter("extra");
        String remark = request.getParameter("remark");
        String province ="";
        String city ="";
        String bankName="";
        String bankNumber ="";
        if ("1".equals(accountAttr)){
            province = request.getParameter("province");         // 开户行所在省份
            city = request.getParameter("city");                 // 开户行所在市
            bankName =request.getParameter("bankName");         // 开户行名称
            bankNumber = request.getParameter("bankNumber");
            if (StringUtils.isEmpty(province) || StringUtils.isEmpty(city)||StringUtils.isEmpty(bankName)
            ||StringUtils.isEmpty(bankNumber) ){
                return ResponseEntity.ok(new BizResponse(10001, "创建订单失败,对公参数为空"));
            }
        }
        BigDecimal amountB = new BigDecimal(amount);
        amountB = amountB.multiply(new BigDecimal("100")).setScale(0);
        MchInfo mchInfo = rpcCommonService.rpcMchInfoService.findByMchId(this.getUser().getId());

        JSONObject retObj = createTransOrder(mchInfo.getMchId(), mchInfo.getPrivateKey(),accountName,accountNo, accountAttr, amountB.toString(), province, city, notifyUrl, bankName,bankNumber, extra,remark);
        if (retObj == null) {
            return ResponseEntity.ok(new BizResponse(10001, "创建订单失败,没有返回数据"));
        }
        if ("SUCCESS".equals(retObj.get("retCode"))) {
            // 验签
            String checkSign = PayDigestUtil.getSign(retObj, mchInfo.getPrivateKey(), "sign");
            String retSign = (String) retObj.get("sign");
            if (checkSign.equals(retSign)) {
                return ResponseEntity.ok(PayPageRes.buildSuccess(retObj));
            } else {
                return ResponseEntity.ok(new BizResponse(10001, "创建订单失败,验证支付中心返回签名失败"));
            }
        }
        return ResponseEntity.ok(new BizResponse(10001, "创建订单失败," + retObj.getString("retMsg")));
    }

    private JSONObject createTransOrder(Long mchId, String privateKey, String accountName, String accountNo, String accountAttr, String amount, String province, String city, String notifyUrl, String bankName, String bankNumber, String extra,String remark) {
        JSONObject paramMap = new JSONObject();
        paramMap.put("mchId", mchId);                               // 商户ID
        paramMap.put("mchOrderNo", System.currentTimeMillis());     // 商户订单号
        paramMap.put("accountAttr", accountAttr);                       // 支付产品
        paramMap.put("amount", amount);                             // 支付金额,单位分
        paramMap.put("accountName", accountName);                           // 账户名称
        paramMap.put("accountNo", accountNo);                                 // 账户号
        paramMap.put("notifyUrl", notifyUrl);                       // 回调URL
        paramMap.put("remark", remark);
        paramMap.put("extra", extra);                               // 附加参数
        String reqTime = DateUtil.getSeqString();
        paramMap.put("reqTime", reqTime);
        if("1".equals(accountAttr)){
            paramMap.put("province", province);
            paramMap.put("city", city);
            paramMap.put("bankName", bankName);
            paramMap.put("bankNumber", bankNumber);
        }
        // 生成签名数据
        String reqSign = PayDigestUtil.getSign(paramMap, privateKey);
        paramMap.put("sign", reqSign);                              // 签名
        String reqData = "params=" + paramMap.toJSONString();
        String url = mainConfig.getPayUrl() + "/df/apply?";
        // 发起Http请求下单
        _log.info("[pay] req:{}--->{}", reqData,url);
        String result = call4Post(url + reqData);
        _log.info("[pay] res:{}", result);
        JSONObject retObj = JSON.parseObject(result);
        return retObj;
    }

    public static void main(String args[]){
        JSONObject paramMap = new JSONObject();
        paramMap.put("mchId", "9000");
        // 商户ID
        String time = System.currentTimeMillis()+ "";
        System.out.println(time);
        paramMap.put("mchOrderNo", time);     // 商户订单号
        paramMap.put("accountAttr", "0");                       // 支付产品
        paramMap.put("amount", "50");                             // 支付金额,单位分
        paramMap.put("accountName", "测试");                           // 账户名称
        paramMap.put("accountNo", "1231121");                                 // 账户号
        paramMap.put("notify_url", "http://150.109.63.144:3502/api/paydemo/notify.htm");                       // 回调URL
        paramMap.put("remark", "ScRipt");
//        paramMap.put("extra", extra);                               // 附加参数
        String reqTime = DateUtil.getSeqString();
        System.out.println(reqTime);
        paramMap.put("reqTime", reqTime);

        // 生成签名数据
        String reqSign = PayDigestUtil.getSign(paramMap, "NYEQPFILBWTUDXNYRSVJUJWBUWLVUISVHDDBFZJYXRWMXNMW1PYITYIGGXVBJNOMRVRUVOUNN7VZZGBXAFTDVVTWBVWYSBAJPXUAQEBNRZIF8M2IOYHBMMCIJIJ70PGW");
        System.out.println(reqSign);
    }
}
